--[[
    加法(__add) 乘法(__mul) 减法（__sub）​、除法（__div）​、
    floor除法（__idiv）​、负数（__unm）​、取模（__mod）和幂运算（__pow）​
    位操作也有元方法：按位与（__band）​、按位或（__bor）​、
    按位异或（__bxor）​、按位取反（__bnot）​、向左移位（__shl）和向右移位（__shr）​。
    __concat来定义连接运算符
    等于（__eq）​、小于（__lt）和小于等于（__le）​。

    函数tostring能将表表示为一种简单的文本格式：函数print总是调用tostring来进行格式化输出。
    不过，当对值进行格式化时，函数tost ring会首先检查值是否有一个元方法__tostring。如果有，
    函数tostring就调用这个元方法来完成工作，将对象作为参数传给该函数，
    然后把元方法的返回值作为函数tostring的返回值。

    当访问一个表中不存在的字段时会得到nil。这是正确的，
    但不是完整的真相。实际上，这些访问会引发解释器查找一个名为__index的元方法
    如果没有这个元方法，那么像一般情况下一样，结果就是nil；否则，则由这个元方法来提供最终结果
]]
metatable = {
    __add=function(mytable,val)
        return mytable.count + val
     end,
     __index = function (_,key)
        return tostring(key)
     end,
    --  __newindex = function(_,key,val)
    --    _[key] = val
    --  end
}
plain_table = {
    count = 1
}
print(getmetatable(plain_table))
-- plain_table.__metatable
setmetatable(plain_table,metatable)
print(getmetatable(plain_table))
print(plain_table + 1)
metatable.__mul = function(mytable,val)
    return mytable.count * val
end
metatable.__tostring = function(mytable,val)
    return mytable.count
end
print(plain_table * 2)
print(plain_table)
print("x",plain_table.x)
--[[
    如果我们希望在访问一个表时不调用__index元方法，
    那么可以使用函数rawget。调用rawget（t,i）会对表t进行原始（raw）的访问，
    即在不考虑元表的情况下对表进行简单的访问。进行一次原始访问并不会加快代码的执行（一次函数调用的开销就会抹杀用户所做的这些努力）​，
    但是，我们后续会看到，有时确实会用到原始访问
]]
print(rawget(plain_table,x))
--[[
    元方法__newindex与__index类似，不同之处在于前者用于表的更新而后者用于表的查询。
    当对一个表中不存在的索引赋值时，解释器就会查找__newindex元方法：如果这个元方法存在，
    那么解释器就调用它而不执行赋值。像元方法__index一样，
    如果这个元方法是一个表，解释器就在此表中执行赋值，而不是在原始的表中进行赋值。
    此外，还有一个原始函数允许我们绕过元方法：调用rawset（t,k,v）来等价于t[k]=v，但不涉及任何元方法。
]]
plain_table.x = 1
print(rawget(plain_table,x))
print(plain_table.x)